<?php
/**********************************************
 error routines
**********************************************/
function terminal_error($err) {
 echo "<h1>A terminal error has occurred</h1>";
 echo $err;
 exit;
}
function nonterminal_error($err) {
 echo "<h1 class=nte>A non terminal error has occurred</h1>";
 echo $err;
}
function micro_time() {
   $timearray = explode(" ", microtime());
	 return ($timearray[1] + substr($timearray[0],0,3) );
}

function sqlreadarray($stmt) {
 $dblink = getconn();
 $results = "";
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  while($row = mysqli_fetch_array($result,MYSQLI_NUM)){
   $results[]=$row;
  }
 }
 mysqli_close($dblink);
 return $results;
}

function sqlreadkeyarray($stmt) {
 $dblink = getconn();
 $results = "";
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  while ($row = mysqli_fetch_array($result,MYSQLI_NUM)) {
   $results[$row[0]] = $row;
  }
 }
 mysqli_close($dblink);
 return $results;
}

function sqlread($stmt) {
 $dblink = getconn();
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
 } else {
  $row = "";
 }
 mysqli_close($dblink);
 return $row;
}

function sqlreaditem($stmt) {
 $dblink = getconn();
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  $field = mysqli_fetch_array($result,MYSQLI_NUM);
 } else {
  $field = "";
 }
 mysqli_close($dblink);
 return $field[0];
}

function sqlexec($stmt) {
 $dblink = getconn();
 $thread_id = mysqli_thread_id($dblink); 
 $result = mysqli_query($dblink,$stmt);
 if ($result !== false) {
//  mysqli_free_result($result);
  mysqli_close($dblink);
 }
// mysqli_kill($dblink,$thread_id);
 return $result;
}

function freaditem($table,$itemid) {
 $dblink = getconn();
 $stmt = "select * from $table where itemid = '$itemid'";
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
 } else {
  $row = "";
 }
 mysqli_close($dblink);
 return $row;
}

function freadfield($table,$itemid,$fname) {
 $dblink = getconn();
 $stmt = "select $fname from $table where itemid = '$itemid'";
 $result = mysqli_query($dblink,$stmt);
 if ($result) {
  $row = mysqli_fetch_array($result,MYSQLI_NUM);
  $ans = @$row[0];
 } else {
  $row = "";
  $ans = "";
 }
 mysqli_close($dblink);
 return $ans;
}

/**********************************************
 date management functions
**********************************************/
function isotojd($indate = ""){
 // Collects a MySQL IS8601 date and returns the gregorian day
 // ISO e.g. is 2009-12-31
 if ($indate =="") {$indate = dtoiso(); }
 $year = substr($indate,0,4);
 $month = substr($indate,5,2);
 $day = substr($indate,8,2);
 return gregoriantojd($month,$day,$year);
}

function isotoout($indate,$time=0) {
 $dtonly = split(" ",$indate);
 $bits = split("-",$dtonly[0]);
 $rev = array_reverse($bits);
 $ans = join("-",$rev);
 if ($time==1) {
  $ans = $ans." ".$dtonly[1];
 }
 return $ans;
}

function jdtoout($inday) {
 // Collects JD and converts it to dateout in locale
 list($m,$d,$y) = explode('/',jdtogregorian($inday));
 return $d."-".$m."-".$y;
}


function dtoiso($indate="") {
 // Collects some user input and converts into iso
 // If blank, always assumes today
 // Initially, only works with DD-MM-TYYY.
 // Note that 05/01/2009 is 1st May and 05-01-2009 is 5th Jan
 // Also note bug in 05/01/09 needs correcting
 $indate= str_replace("/","-",$indate);
 $arr = split("-",$indate);
 
 if (sizeof($arr) == 3) {
  $y = $arr[2];
	if ($y < 100) {
	 $y=$y+2000 ;
	 $arr[2] = $y;
	 $indate = $arr[0]."-".$arr[1]."-".$arr[2];
	}
 }
 if (sizeof($arr) == 2) {$indate = $indate."-".date("Y");}
 $ans = strtotime($indate);
($ans == "") ? $ans = date("Y-m-d") : $ans = date("Y-m-d",$ans);
 return $ans;
}

/*****************************************************
* Connection functions
* Note this is not database independent. It is MYSQL 5.1
*****************************************************/
function getconn() {
 // hard code because these values do not get used anywhere else
 if ($_SERVER["REMOTE_ADDR"] == "127.0.0.1") {
  $dblink = mysqli_connect("127.0.0.1","tradedb","tradedb","tradedb");
 } else {
  $dblink = mysqli_connect("127.0.0.1","tradedb","tradedb","tradedb");
//  $dblink = mysqli_connect("mysql1.webbase.net.nz","tradedb","trade1db","tradedb");
 }
 if (!$dblink) terminal_error("E01 : Serious connection error");
 return $dblink;
}

function getcounter($type,$section) {
 $dblink = getconn();
 $comm = "call uniqueid('".$type."','".$section."')";
 $result = mysqli_query($dblink,$comm);
 if (!$result) terminal_error("E02 : Serious counters error");
 $row = mysqli_fetch_array($result);
 if (!$row) terminal_error("E03 : Missing counters error");
 mysqli_close($dblink);
 return $row[0];
/*
for mysql:
Needs mysql 5.0 or later
CREATE DEFINER=`root`@`localhost` PROCEDURE `uniqueid`(doctype char(3),unit char(4))
BEGIN
 start transaction ;
 select concat(prefix,cnt) from counters where doctype = counters.doctype and unit = counters.unit for update;
 update counters set cnt=cnt+1 where doctype = counters.doctype and unit=counters.unit      ;
 commit;
END
create table counters doctype chsr(3) , unit mediumint(9), prefix char(10)< cnt mediumint(9)
*/
}
/*****************************************************
* Authentication functions
*****************************************************/

function authenticate($prompt = true) {
 // user item[0] = user item from registereduser table. [group] = 1, [group] = 1 etc
 if (isset($_SESSION["user"])) { 
  return $_SESSION["user"];
 } elseif (isset($_REQUEST["userid"]) && isset($_REQUEST["password"])) {
   $userid = $_REQUEST["userid"];
   $password = $_REQUEST["password"];
   if (strlen($userid) > 0 && strlen($password) > 0) {
    $user = authenticatedb($userid,$password) ;
    if ($user !== "") {
     $_SESSION["user"] = $user;
     if (isset($_REQUEST["cookie"])) {
      setcookie("user",$user[0]['itemid'].'|'.$user[0]['activateword'],time()+360000);
     } else {
      setcookie("user",time()-3600);
     }
  	 return $user;
  	}
	 }
 } elseif (isset($_REQUEST["code"])) {
  $c = $_REQUEST["code"]; 
  $user = authenticatedb($c,"") ;
  if ($user !== "") {
   $_SESSION["user"] = $user;
   return $user;
  }
 } elseif (isset($_COOKIE["user"])) {
  $cookieid = $_COOKIE["user"];
  $user = authenticatedb($cookieid,""); 
  if ($user != "") {
   $_SESSION["user"] = $user;
   return $user;
  }
 }
 if ($prompt) {
  include 'showlogin.php';
  exit ;
 } else {
  return false;
 }
}

function authorise($group) {
 $groups = authenticate(1);
 if (isset($groups[$group])) return true;
 terminal_error("E08: You are not authorised to access this resource");
}

function authenticatedb($userid,$password) {
 // registereduser userid,password,name etc. userid is primary key
 // groups userid,group no primary key
 $dblink = getconn();
 $userid = mysqli_real_escape_string($dblink,$userid);
 $stmt = "select * from registereduser,authgroup ";
 $stmt .= "where registereduser.itemid = authgroup.registereduser";
 if ($password !== "") {
  $stmt .= " and registereduser.email = '$userid'";
  $password = md5(mysqli_real_escape_string($dblink,$password));
  $stmt .= " and registereduser.password = '$password'";
 } else { 
  $i = explode("|",$userid);
  $stmt .= " and registereduser.itemid = '$i[0]'";
  if (isset($i[1])) {
   $stmt .= " and registereduser.activateword = '$i[1]'";
  } else {
   $stmt .= " and 1=0";
  }
 }
 $result = mysqli_query($dblink,$stmt);
 $groups = "";
 $useritem = "";
 while ($row = mysqli_fetch_array($result,MYSQLI_ASSOC)) {
  $useritem[0] = $row;
  $useritem[$row['grp']] = "1";
 }
 mysqli_close($dblink);
 return $useritem;
}

/*********************************************************************
  head class for single dimensional data rows
*********************************************************************/
abstract class obj {

 public $lastsearchresults = "";
 public $lastsearch = "";
 public $lastsearchheader = "<tr><td>Id</td><td>Name</td></tr>";
 public $header = "";
 public $atts = 0;
 protected $table = "";
 public $metadata = ""; 
 public $valid = false;
 public $valids = "";
 public $refs = "";
 public $lists = "";
 public $help = "";
 public $origheader ;
 public $origlines ;
 public $disabled = '' ;
 
 function validatefield($i,$t,$forcelookup="N") {
  // $i = field number, $t = table
  $f = @$_REQUEST["f$i"];
  if ($forcelookup=="Y" && $f == NULL) {$f=$this->header[$i];}
	if ($f !== NULL) {
	 if ($f == ' ') {
	  $desc = "";
	  $this->header[$i] = "";
	 } else {
    $desc = freaditem($t,$f);
    if ($desc == '') {
     $this->valids[$i] = "Need valid $t code";
     $this->lists[$i] = $this->selectlisth($t,$f,"f$i");
    } else {
     $this->header[$i] = $f;
     $this->refs[$i] = $desc[1];
     $this->lists[$i] = '';
    }
   }
  }
 }
 
 function confirmfiled($itemid=null) {
  echo "<br><br>";
  echo "<body onload='document.form.sub.focus()'>";
  echo "<h1>$itemid Filed as requested</h1>";
  echo "<form>";
  echo "<input class=bt accesskey=C type=submit name=sub value='Continue'>";
  echo "</form>";
 }


 function confirmdeleted($itemid=null) { 
  // To preserve integrity, you are almost always going to override this.
  echo "<br><br>";
  echo "<body onload='document.form.sub.focus()'>";
  echo "<h1>$itemid Deleted as requested</h1>";
  echo "<form>";
  echo "<input class=bt accesskey=C type=submit name=sub value='Continue'>";
  echo "</form>";
 }

 function showfail() {
  echo "<br><br>";  
  echo "<body onload='document.form.sub.focus()'>";
  if($this->result <> "") {
   echo "<h1>".$this->result."</h1>";
  } else {
   echo "<h1>Failed to file. Click to return to document</h1>";
  }
  echo "<form name=form>";
  echo "<input accesskey=C class=bt type=submit name=sub value=Continue>";
  echo "</form>";
 }
 
 function selectlist($condition) {
  // Last search cached for speed.
  if ($condition == $this->lastsearch && $condition !=="ALL") {
    return $this->lastsearchresults;
  } else {
	  $stmt = "select itemid,name from ".$this->table;
	  $words = explode(" ",$condition);
	  if ($condition !=="" and $condition !=="ALL") {
	   if (sizeof($words > 0)) {
	    $stmt .= " where name like '%$words[0]%'";
	    for ($i=1;$i<sizeof($words);$i++) {
	     $stmt .= " and name like '%$words[$i]%'";
	    }
	   } else {
	    $stmt .= " where name like '%$condition%'";
	   }
	  }
	  $stmt .= " order by editdate desc limit 1000";
	  $ans = sqlreadarray($stmt);
	  $this->lastsearchresults = $ans;
	  $this->lastsearch = $condition;
    return $ans;
  }
 }

 function selectlisth($table,$condition,$fn,$addnothing=true) {
  if (is_array($table)) {
   $arr = $table;
//   $addnothing = false;
  } else {
  $stmt = "select itemid,name from ".$table;
  if ($condition !=="" and $condition !=="ALL") {
   if (substr($condition,0,5) == "where") {
    $stmt .= " ".$condition;
   } else {
    $words = explode(" ",$condition);
    if (sizeof($words > 0)) {
     $stmt .= " where name like '%$words[0]%'";
     for ($i=1;$i<sizeof($words);$i++) {
      $stmt .= " and name like '%$words[$i]%'";
     }
    } else {
     $stmt .= " where name like '%$condition%'";
    }
   }
  }
  $stmt .= " LIMIT 30";
  $arr = sqlreadarray($stmt);
  }
  $h = "";
  if ($arr) {
   $h = "<select name=$fn>";
   foreach ($arr as $item) {
    $h .= "<option value='$item[0]'>$item[0] - $item[1]</option>\n";
   }
   if ($addnothing) {
    $h .= "<option value='[]'>Nothing in this list</option>\n";
   }
   $h .= "</select>\n";
  }
  return $h;
 }
  // Choose from a list
 function showchoose($head = "Choose From List",$prompt="Enter to create a new item, or enter code") {
  (isset($_REQUEST["from"])) ? $frm=$_REQUEST["from"] : $frm=0;
  (isset($_REQUEST["itemid"])) ? $id=$_REQUEST["itemid"] : $id='ALL';
  echo "<h1>$head</h1>";
  echo "<body onload='document.form.itemid.focus()'>";
  echo "<form name='form' method=POST>";
  echo "<input type=hidden name=from value=0>";
  echo "<table>"; 
  echo "<tr>";
  echo "<td>Choose</td>";
  echo "<td>";
  echo "<input name=itemid>";
  echo "</td>";
  echo "<td>$prompt</td>";
  echo "</tr>";
  echo "</table>";
  echo "<input class=bt type=submit name=sub value=Submit>";
  echo "</form>"; 
  print "<p>";
  $list = $this->selectlist($id);
  if ($list == "") {
   echo "<p>List empty when searching for $id. Type ALL to search for all items</p>";
  } else {
   $max=15 ;
   $o = "";
   if ($frm > 0) {
    $prevpage = $frm-$max;
    if ($prevpage<0) $prevpage=0;
    echo "<a class=m2 href=?itemid=".urlencode($id)."&from=$prevpage>Previous page</a>";
   }
   $o .= "<table>";
   $o .= $this->lastsearchheader;
   for ($i=$frm;$i<($max+$frm) && $i<sizeof($list);$i++) {
    $value = $list[$i];
    $o.= "<tr>";
    $o.= "<td><a class=m1 href=?itemid={$value[0]}>{$value[0]}</a></td>";
    for ($j=1; $j < sizeof($value) ; $j++) {
		 $o.= "<td>{$value[$j]}</td>"; 
		}
    $o.= "</tr>";
   }
   $o.= "</table>";
   echo $o;
   if ($i < sizeof($list)) {
    echo "<a href=?itemid=".urlencode($id)."&from=$i>More</a>"; 
   }
  }
 }

 function htmlrow($p,$name = null,$disabled = "") {
   if ($disabled=="") {$dis = $this->disabled;} else {$dis = $disabled;}
   if ($name==null) $name = $this->metadata[$p]->name ;
   $o = "<tr>";
   $o .= "<td>".$name."</td>";
   if (@$this->lists[$p] == "") {
    $o .= "<td>";
    $o .= "<input $dis id='id".$name."' name=f$p size=".min(45,$this->metadata[$p]->length)." maxlength=".$this->metadata[$p]->length.' value="'.$this->header[$p].'">';
    $o .= $this->refs[$p];
    $o .= "</td>";
   } else {
    $o .= "<td>".$this->lists[$p]."</td>";
   }
   $o .= "<td>".$this->valids[$p]."</td>";
   $o .= "</tr>";
   return $o;
 }
 function markedited() {
  $this->header[3] = date("Y-m-d H:i:s");
	$user = authenticate(0); 
  $this->header[4] = $user[0]['itemid'];
 }
 
}

abstract class head extends obj {
 // Master table class for single dimensional records
 
 abstract function applyfromrequest(); // Must be overrridden
 abstract function showform();

 function gettablename() {return $this->table;}
 
 function getmetadata() {
  // For speed - keep this in the user session
  if (isset($_SESSION[$this->table."_METADATA"])) {
   $this->metadata = $_SESSION[$this->table."_METADATA"];
  } else {
   $dblink=getconn();
   $result = mysqli_query($dblink,"select * from $this->table where 1=0");
   if (!$result) {terminal_error("Missing table $this->table");};
   $this->metadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_METADATA"] = $this->metadata;
   mysqli_close($dblink);
  }
  $this->atts = sizeof($this->metadata);
 }

 function createblank() {
  $this->header = array_fill(0,$this->atts,"");
  $this->header[2] = "0";
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
 }   
 

 function registerhelp() {
  $this->gethelp() ;
  $o = "";
	if ($this->help) {
   $ecs = "";
   foreach ($this->help as $rec){
    $o.= "<span id=hlp{$rec[0]} class='hlp' >\n";
    $o.= $rec[1]."\n";	
    $o.= "</span>\n";
    $ecs .= "addevents('{$rec[0]}'); ";
   }
   $o.= "<script>$ecs</script>";
  }
  return $o;
 }
 
 function gettablelist() {
  $ans = array("branch","customer","area","gst","salesman");
  return $ans;
 }
 
 function gethelp() {
  // For speed - keep this in the user session
  $u = authenticate("0");
  
  if ($u[0]['showhelp'] == "Y") {
   if (isset($_SESSION[$this->table."_HELP"])) {
    $this->help = $_SESSION[$this->table."_HELP"];
   } else {
    $stmt = "select fieldname,note from help where tablename = '".$this->table."'";
    $result = sqlreadarray($stmt);
    if ($result) {
     $this->help = $result;  
     $_SESSION[$this->table."_HELP"] = $this->help;
    } else {
     $_SESSION[$this->table."_HELP"] = "";;
    }
   }
  }
 }
 
 function readdb($itemid) {
   if ($itemid == "ALL" || $itemid == "") return false;
   $ans = freaditem($this->table,$itemid);
   if ($ans == "") {
    return false;
   } else {
  	$this->header = $ans;
    $this->origheader = $ans;
    $this->applyrefs();
    $this->setdisabled();
    return true;
   }
 }
 
 function setdisabled() {
  $this->disabled = '';
 }

 function applyrefs() {
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
 }
 
 function newcounter() {
  return $this->header[0];
 }
 
 function deletedb() {
  $success = true;
  $dblink = getconn();
  $sql = "delete from $this->table where itemid = '{$this->header[0]}'";
  $ans = sqlexec($sql);
  if (!$ans) {
   $this->result = "E05: Unable to delete - likely this is being referred to by another table\n";
   $success = false;
  };
  if ($success) {unset($_SESSION[$this->table]);}
  
  mysqli_close($dblink);
  return $success;
 }

 function writedb() {
  $success = true;
  $dblink = getconn();
  foreach ($this->header as $id=>$item) {
   $this->header[$id] = mysqli_real_escape_string($dblink,$item);
  }
  $this->markedited();
  if ($this->header[2] == "0") {
   $this->header[2] = 1;
   $this->header[0] = $this->newcounter();
   $stmt = $this->makeinsertsql();
  } else {
   $stmt = $this->makeupdatesql();
  }
  
  $this->result = mysqli_query($dblink,$stmt);
  if ($this->result) {
	 unset($_SESSION[$this->table]);
  } else {
	 $this->result = "E04: ".mysqli_error($dblink)."\n";
	 nonterminal_error($this->result);
	 $this->header[2] -= 1;
	 $success = false;
	}
  mysqli_close($dblink);
  return $success;
 }
 
 function unload() {
  unset($_SESSION[$this->table]);
 }
 
 function makeinsertsql() {
   $stmt = "insert into $this->table values (";
   for ($i=0;$i<$this->atts-1;$i++) {
     $stmt .= "'".$this->header[$i]."',";
   }
	 $stmt .= "'".$this->header[$this->atts-1]."')";

   return $stmt;  
 }
 
 function makeupdatesql() {
  $this->header['2'] += 1;
  $stmt = "update $this->table set ";
  for ($i=1;$i<$this->atts-1;$i++) {
   $stmt .= $this->metadata[$i]->name." = '".$this->header[$i]."', ";
  }
  $stmt .= $this->metadata[$i]->name." = '".$this->header[$i]."' ";
  $stmt .= " where itemid = '".$this->header[0]."' ";
  return $stmt;
 }
  
}

/*********************************************************************
  2D Class for two-table objects. For example purchase orders, sales orders
  porder, porderline
  sorder, sorderline
*********************************************************************/
abstract class head2d extends obj {
 public $lineatts = 0 ;
 protected $linetable = "";

 public $linemetadata ;
 public $linehelp = "";
 
 public $lines ;
 public $linevalids ;
 public $linerefs;
 public $linelists;

 public $currentline;
 public $currentlinevalids;
 public $currentlinerefs;
 public $currentlinelists;

 function createblank() {
  $this->header = array_fill(0,$this->atts,"");
  $this->header[2] = "0";
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
  $this->currentline = array_fill(0,$this->lineatts,"");
  $this->currentlinerefs = array_fill(0,$this->lineatts,"");
  $this->currentlinevalids = array_fill(0,$this->lineatts,"");
  $this->currentlinelists = array_fill(0,$this->lineatts,"");
  $this->editline = 0;  
 } 
 
 abstract function applyfromrequest(); // Must be overrridden
 abstract function showform();
 
 function gettablename() {return $this->table;}

 function calcgst($lines = null) {
  if ($lines == null) {$lines=$this->lines;}
  $arr = sqlreadkeyarray("select * from gst");
  $goods = 0; $gst = 0;
  foreach ((array) $lines as $line) {
    // Decide on a rate line-by-line
    $rateid = $line[12];
    $rate = @$arr[$rateid][5];
    $linegoods = $line[4]*100/$line[3]*$line[6];
    $gst += floor($rate*$linegoods/100+.49)/100;
    $goods += floor($linegoods)/100;
  }
  return array($goods,$gst);
 }
 
 function registerhelp() {
  $hlp = (array)$this->gethelp() ; // Also adds errors
  $o = "";
  $ecs = "";
  foreach ($hlp as $id=>$val){
    $o.= "<span id=hlp$id class='hlp' >\n";
    $o.= $val."\n";
    $o.= "</span>\n";
    $ecs .= "addevents('$id'); ";
  }
  $o.= "<script>$ecs</script>";
  return $o;
 }
  
 function getmetadata() {
  //For speed - keep this in the user session
  if (isset($_SESSION[$this->table."_METADATA"])) {
   $this->metadata = $_SESSION[$this->table."_METADATA"];
  } else {
   $dblink=getconn();
   $result = mysqli_query($dblink,"select * from $this->table where 1=0");
   if (!$result) {terminal_error("Missing table $this->table");};
   $this->metadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_METADATA"] = $this->metadata;
   mysqli_close($dblink);
  }
   
  $this->atts = sizeof($this->metadata);
  if (isset($_SESSION[$this->table."_LINEMETADATA"])) {
   $this->linemetadata = $_SESSION[$this->table."_LINEMETADATA"];
  } else {
   $dblink=getconn();
   $stmt = "select * from ".$this->linetable." where 1=0";
   $result = mysqli_query($dblink,$stmt);
   if (!$result) {terminal_error("Missing table ".$this->linetable);};
   $this->linemetadata = mysqli_fetch_fields($result);
   $_SESSION[$this->table."_LINEMETADATA"] = $this->linemetadata;
   mysqli_close($dblink);
  }

  $this->lineatts = sizeof($this->linemetadata);
 }
 
 function gethelp() {
  // For speed - keep this in the user session
  $u = authenticate("0");
  
  if ($u[0]['showhelp'] == "Y") {
   if (isset($_SESSION[$this->table."_HELP"])) {
    $this->help = $_SESSION[$this->table."_HELP"];
   } else {
    $stmt = "select fieldname,note from help where tablename = '".$this->table."'";
    $result = sqlreadarray($stmt);
    // Convert to id keyed array
    $ans = "";
    if ($result) {foreach ($result as $v) $ans[$v[0]] = $v[1];}
    if ($ans) {
     $this->help = $ans;  
     $_SESSION[$this->table."_HELP"] = $this->help;
    } else {
     $_SESSION[$this->table."_HELP"] = "";;
    }
   }
  }
  $hlp = $this->help;
  // Add on any errors;
  foreach((array)$this->currentlinevalids as $no=>$name) {
   if ($name) {
    $hlp["l".$no] = $name;
   }
  }
  return $hlp;  
 }
 
 function readdb($itemid) {
   if ($itemid == "ALL" || $itemid == "") return false;
   $ans = freaditem($this->table,$itemid);
   if ($ans == "") {
    return false;
   } else {
  	$this->header = $ans;
    $this->origheader = $ans;
    $this->applyrefs();
    $ans = sqlreadarray("select * from $this->linetable where itemid='".$itemid."' order by seq");
    if ($ans != "") {
     $this->lines = $ans;
     $this->origlines = $ans;
     $this->applylinerefs();
     $this->setdisabled();
    }
    $this->currentline=$this->defaultline();
    return true;
   }
 }
 
 function setdisabled() {
  $this->disabled = '';
 }

 function applyrefs() {
  $this->valids = array_fill(0,$this->atts,"");
  $this->lists = array_fill(0,$this->atts,"");
  $this->refs = array_fill(0,$this->atts,"");
 }
 
 function applylinerefs() {
  $this->linevalids = array_fill(0,$this->lineatts,"");
  $this->linelists = array_fill(0,$this->lineatts,"");
  $this->linerefs = array_fill(0,sizeof($this->lines),array_fill(0,$this->lineatts,""));
 }

 
 function defaultline() {
  $ans = array_fill(0,$this->lineatts,"");
  return $ans;
 }
 
 function newcounter() {
  return $this->header[0];
 }
 
 function deletedb() {
  $success = true;
  $dblink = getconn();

  $sql = "delete from $this->table where itemid = '{$this->header[0]}'";
  $ans = sqlexec($sql);
  if (!$ans) {
   $this->result = "E05: Unable to delete - likely this is being referred to by another table\n";
   $success = false;
  } else {
   $sql = "delete from $this->linetable where itemid = '".$this->header[0]."'";
   $ans = sqlexec($sql);
   if (!$ans) {
    $this->result = "E05: Unable to delete ".mysqli_error($dblink)."\n".$sql;
    $success = false;
   };
  }
  if ($success) {unset($_SESSION[$this->table]);}

  mysqli_close($dblink);
  return $success;
 } 

 function writedb() {
  $success = true;
  $dblink = getconn();
  // get rid of any possible injection 
  foreach ($this->header as $id=>$item) {
   $this->header[$id] = mysqli_real_escape_string($dblink,$item);
  }
  if (is_array($this->lines)) {
   foreach ($this->lines as $id=>$item) {
    foreach ($item as $pos=>$field) {
     $this->lines[$id][$pos] = mysqli_real_escape_string($dblink,$field);
    }
   }
  }
  // Add user info and edit date
  $this->header[3] = date("Y-m-d H:i:s");

 	$u = authenticate(0); 
  $this->header[4] = $u[0]['itemid'];
  // If inserting
  if ($this->header[2] == "0") {
   $this->header[2] = 1;
   $this->header[0] = $this->newcounter();
   $stmt = $this->makeinsertsql();
  } else {
   // editing
   $stmt = $this->makeupdatesql();
  }
  // execute query one line at a time
  foreach($stmt as $sql) {
   $r = mysqli_query($dblink,$sql);
   if (!$r) {
	  $success = false;
    nonterminal_error("E04: ".mysqli_error($dblink)."\n");
    echo $sql;
	 }
  }
  // deal with results
  if ($success) {
	 $_SESSION["lastid"] = $this->header[0] ;
	 unset($_SESSION[$this->table]);
	}
  mysqli_close($dblink);
  return $success;
 }
 
 function makeinsertsql() {

   $multisql = "";
   // Do the header first
   $sql = "insert into $this->table values (";
   for ($i=0;$i<$this->atts-1;$i++) {
     $sql .= "'".$this->header[$i]."',";
   }
	 $sql .= "'".$this->header[$this->atts-1]."')";
	 $multisql[] = $sql;
	 // Then do the lines
   for ($l=0;$l<sizeof($this->lines);$l++) {
     $value = $this->lines[$l];
     $value[0] = $this->header[0];
     $value[1] = $l;
     for ($i=0;$i<$this->lineatts;$i++) {
			$sql = "insert into $this->linetable values(";
			for ($i=0;$i<$this->lineatts-1;$i++) {
 			 $sql .= "'".$value[$i]."',";
			}
			$sql .= "'".$value[$this->lineatts-1]."')";
			$multisql[] = $sql ;
     }
   }
   return $multisql;  
 }
  
 function makeupdatesql() {
  // header
  $this->header['2'] += 1;
  $multisql = "";
  $sql = "update $this->table set ";
  for ($i=1;$i<$this->atts-1;$i++) {
   $sql .= $this->metadata[$i]->name." = '".$this->header[$i]."', ";
  }
  $sql .= $this->metadata[$i]->name." = '".$this->header[$i]."' ";
  $sql .= " where itemid = '".$this->header[0]."';\n"; 
  $multisql[] = $sql;
  // Do the lines next. Note that this is theoretically inefficient. If one
  // line gets edited, the whole lot get scrapped and put in again.
  // Before overriding, here are some considerations:
  //  - Two deletes + one change + one insert may not be any quicker than 4 deletes+4 inserts
  //  - Line numbers change during edits.
  //  - Ensure you have a speed bottleneck in the database itself before going to the effort.
  $sql = "delete from $this->linetable where itemid = '".$this->header[0]."'";
  $multisql[] = $sql;
  for ($l=0;$l<sizeof($this->lines);$l++) {
     $value = $this->lines[$l];
     $value[0] = $this->header[0];
     $value[1] = $l;
     for ($i=0;$i<$this->lineatts;$i++) {
			$sql = "insert into $this->linetable values(";
			for ($i=0;$i<$this->lineatts-1;$i++) {
 			 $sql .= "'".$value[$i]."',";
			}
			$sql .= "'".$value[$this->lineatts-1]."')";
			$multisql[] =$sql;
     }
   }	 
   
  return $multisql;
 }
 
 function localprint() {
  echo "<body onload='document.form.sub.focus(); window.print();'>";
  echo "<form name=form>";
  echo "<input name=sub class=bt type=submit value='Click to Continue'>";
  echo "</form>";
  echo "</body>";
 }
 
 function emailatt($att) {
  $message = "PDF ATTACHED";
  $file = chunk_split(base64_encode($att)); 
  $num = md5(time()); 
  $headers  = "From: Name<name@name.com>\r\n"; 
  $headers  .= "MIME-Version: 1.0\r\n"; 
  $headers  .= "Content-Type: multipart/mixed; "; 
  $headers  .= "boundary=".$num."\r\n"; 
  $headers  .= "--$num\r\n"; 
  $headers .= "Content-Type: text/html; charset=iso-8859-1\r\n"; 
  $headers .= "Content-Transfer-Encoding: 8bit\r\n"; 
  $headers .= $message."\n"; 
  $headers .= "--".$num."\n";  
  $headers  .= "Content-Type:application/pdf "; 
  $headers  .= "name=name.pdf r\n"; 
  $headers  .= "Content-Transfer-Encoding: base64\r\n"; 
  $headers  .= "Content-Disposition: attachment; "; 
  $headers  .= "filename=pdffile.pdf \r\n\n"; 
  $headers  .= "".$file."\r\n"; 
  $headers  .= "--".$num."--";       
  mail('antonylawler@gmail.com', 'pdf', 'body', $headers); 
 }

 function htmlline($p,$name = null, $disabled = "") {
   if ($disabled=="") {$dis = $this->disabled;} else {$dis = $disabled;}
   if ($name==null) $name = $this->linemetadata[$p]->name ;
   $o = "<tr>";
   $o .= "<td>".$name."</td>";
   if (!isset($this->currentlinelists[$p])) {
    $o .= "<td>";
    $o .= "<input $dis id='id".$name."' name=l$p size=".min(45,$this->linemetadata[$p]->length)." maxlength=".$this->linemetadata[$p]->length.' value="'.$this->currentline[$p].'">';
    if (isset($this->currentlinerefs[$p])) {
     $o .= $this->currentlinerefs[$p];
    }
    $o .= "</td>";
   } else {
    $o .= "<td>".$this->currentlinelists[$p]."</td>";
   }

   $o .= "<td>".$this->currentlinevalids[$p]."</td>";
   $o .= "</tr>";
   return $o;
 }
  
}

/*********************************************************************
  other
*********************************************************************/
function generatepassword (){
  $password = "";
  $possible = "abcdfghjkmnpqrstvwxyz"; 
  for ($i=0;$i<8;$i++) {
    $password .= substr($possible, mt_rand(0, strlen($possible)-1), 1);
  }
  return $password;
}

function validateemail($email) {
 if(eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email)) {
  return true;
 } else {
  return false;
 }
}

function every($array,$value) {
 if (is_array($array)) {
  foreach($array as $id=>$val) {
   if ($val !== $value) return false;
  }
 } else {
  if ($value=="") {
   return true;
  } else {
   return false;
  }
 }
 return true;
}

function iscurrency($instring) {
 $v1 = $instring*100;
 $v2 = floor($v1+.05);
 $v1 = $v1."";
 $v2 = $v2."";
 if ($v1==$v2 ) {
  return true;
 } else {
  return false;
 }
}

function xd($x) {
 print "<pre>";
 print "\n\n\n\n\n\n\n\n";
 print_r($x);
}

function xdtab($x) {
 print "<table>";
 print "<tr>";
 foreach ($x as $v) {
  print "<td>$v</td>";
 }
 print "</tr>";
 print "</table>";
}

define ('SCRIPTS',"
  <script>
  function rest() {
   if (confirm('Lose all changes - you sure ?')) {
    document.form.res.value='restart';
    document.form.submit();
   }
  }
  function submitform1(vl) {
   document.form.editline.value=vl;
   document.form.submit();
  }
  function submitform2(vl) {
   document.form.x.value=vl;
   document.form.submit();
  }
  function addevents(elid) {
   obj = document.getElementById('id'+elid);
   if (obj) {
    if (document.addEventListener) {
     obj.addEventListener('focus',function() {document.getElementById('hlp'+elid).style.visibility='visible'} , false);
     obj.addEventListener('blur',function() {document.getElementById('hlp'+elid).style.visibility='hidden'} , false);
    } else {
     obj.attachEvent('onfocus',function() {document.getElementById('hlp'+elid).style.visibility='visible'});
     obj.attachEvent('onblur',function() {document.getElementById('hlp'+elid).style.visibility='hidden'});
    }
   } else {
    //  alert ('Cannot give help on ' + elid);
   }
  }
  </script>
  ")

?>